/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ambimmort.ucagent.modules.server;

import cn.net.greenet.db.HibernateUtil;
import cn.net.greenet.db.bean.*;
import cn.net.greenet.iprange.info.SearchIpUserRelation;
import com.ambimmort.ucagent.modules.server.codec.UcRawMessage;
import com.ambimmort.ucagent.modules.server.dpi.DPIEndPoint;
import com.ambimmort.ucagent.modules.server.dpi.DPIEndPointManager;
import com.ambimmort.ucagent.modules.webservice.Cacher;
import com.ambimmort.ucagent.modules.webservice.Thing;
import com.ambimmort.ucagent.utils.HexUtil;
import com.ambimmort.ucagent.utils.IdUtils;
import com.ambimmort.umessage.UcType;
import com.ambimmort.umessage.uc.incoming.xC2;
import com.ambimmort.umessage.uc.outgoing.uvm.x83;
import net.sf.json.JSONObject;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.hibernate.Session;
import org.hibernate.Transaction;

import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author 定巍
 */
public class UcAgentServerHandler extends IoHandlerAdapter {

    private Map<IoSession, DPIEndPoint> dpiEndPoints = new HashMap<IoSession, DPIEndPoint>();

    private Map<IoSession, Session> hibernateSessions = new HashMap<IoSession, Session>();

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void sessionOpened(IoSession session) throws Exception {

        if (hibernateSessions.containsKey(session)) {
            hibernateSessions.remove(session);
            hibernateSessions.put(session, HibernateUtil.getSessionFactory().openSession());
        } else {
            hibernateSessions.put(session, HibernateUtil.getSessionFactory().openSession());
        }

        InetSocketAddress addr = (InetSocketAddress) session.getRemoteAddress();
        System.out.println("server connect: " + addr.getAddress().getHostAddress() + " | iosession: " + session.getId() + " | Handler:" + this);
        if (DPIEndPointManager.getInstance().getEndPoints().containsKey(addr.getAddress().getHostAddress())) {
            DPIEndPoint ep = null;

            if (addr.getAddress().getHostAddress().equals("127.0.0.1")) {
                ep = DPIEndPointManager.getInstance().getEndPoints().get("127.0.0.1");
            } else {
                ep = DPIEndPointManager.getInstance().getEndPoints().get(addr.getAddress().getHostAddress());
            }

            System.out.println("Address:" + addr.getAddress().getHostAddress());
            if (dpiEndPoints.containsKey(session)) {
                dpiEndPoints.remove(session);
            }
            dpiEndPoints.put(session, ep);
            ep.getDpiEndPointBean().setIsServerChannelConnected(true);
            ep.persistence();
        } else {
            System.out.println("server rejected: " + addr.getAddress().getHostAddress());
            session.close(true);
        }
    }

    @Override
    public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
        cause.printStackTrace();
    }

    @Override
    public void messageReceived(IoSession session, Object message) throws Exception {

        UcRawMessage rmsg = (UcRawMessage) message;

        Messageincominglog log = new Messageincominglog(dpiEndPoints.get(session).getDpiEndPointBean());
        log.setFromIp(((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress());
        log.setMessageNo(rmsg.getMessageNo().toInteger());
        log.setMessageSequenceNo(rmsg.getMessageSequenceNo().toLong());
        log.setMessageType(HexUtil.getHex(rmsg.getMessageType().toByte()));
        log.setPacket(rmsg.getBytes());
        log.setTime(new Date(System.currentTimeMillis()));
        log.setId(IdUtils.getId(log));
        Thing addThing = new Thing();
        addThing.setAction(Thing.ADD);
        addThing.setData(log);
        Cacher.getInstance().addTing(addThing);
        Session sess = hibernateSessions.get(session);
        Transaction tx = null;
//        sess.save(log);
//        tx.commit();

//        System.out.println("msg [" + session.getRemoteAddress() + "][logId:" + log.getId() + "]: " + rmsg.toString());
        byte mt = rmsg.getMessageType().toByte();
        if (mt == (byte) 0xc2) { //策略同步请求
            xC2 c2 = new xC2();
            try {
                c2.parseBinary(rmsg.getBytes());
            } catch (Exception e) {
                System.out.println("msg error [" + session.getRemoteAddress() + "], check logId : " + log.getId());
//                Transaction tx1 = sess.beginTransaction();
//                log.setMessageSerialNo(-2l);
//                sess.update(log);
//                tx1.commit();
                return;
            }

            Dpiendpointbean dpiBean = (Dpiendpointbean) hibernateSessions.get(session).get(Dpiendpointbean.class, dpiEndPoints.get(session).getDpiEndPointBean().getId());

            Map<String, Integer> map = new HashMap<String, Integer>();
            Policyrepositoryinstance priPtr = null;
            for (Object piObj : dpiBean.getPolicyrepositoryinstances()) {
                priPtr = (Policyrepositoryinstance) piObj;
                map.put(priPtr.getPolicyrepositorytype().getMessageType(), priPtr.getId());
            }
            String msgType = null;
            msgType = "0x" + com.ambimmort.umessage.util.HexUtil.getHex(rmsg.getMessageType().toByte());
            if (map.containsKey(msgType)) {
                try {
                    tx = sess.beginTransaction();
                    Versionreported vr = new Versionreported();
                    vr.setDpiendpointbean(dpiBean);
                    vr.setPolicyrepositoryinstance((Policyrepositoryinstance) sess.get(Policyrepositoryinstance.class, map.get(msgType)));
                    VersionreportedId vid = new VersionreportedId(dpiBean.getId(), map.get(msgType));
                    vr.setId(vid);
                    vr.setMessageSerialNo(c2.getMessageSerialNo().toLong());
                    vr.setReportTime(log.getTime());
                    sess.saveOrUpdate(vr);
                    tx.commit();
                    sess.evict(vr);
                } catch (Exception e) {
                    e.printStackTrace();
                    tx.rollback();
                }
            }
        } else if (mt == (byte) 0x83) {

//            x83 msg = new x83();
//            msg.parseBinary(rmsg.getBytes());
//            String label = "[AAA Query:" + msg.getUserIP() + " from " + dpiEndPoints.get(session).getDpiEndPointBean().getName() + "]";
//            System.out.println("==>" + label + "\n" + msg.toJSON());
//            int queryType = msg.getQuery_Type().toByte();
//            if (queryType == 1) {
//                String ip = msg.getUserIP().toString();
//                String AAAServerIP = SystemPropertyUtil.getInstance().getProperty("mongodb.ip");
//                QueryAAA t = new QueryAAA(AAAServerIP);
//                try {
//                    System.out.println("=>Query AAA Server:" + AAAServerIP);
//                    byte[] body = null;
//                    try {
//                        body = t.queryIpv4AAA(queryType, ip, msg.getUserPortSegStar().toInteger(), msg.getUserPortSegEnd().toInteger());
//                    } catch (Throwable th) {
//                        System.out.println("=>Query AAA Server Error:" + th.toString());
//                        th.printStackTrace();
//                    }
//                    System.out.println("=>Query AAA Server Finished : " + (body == null ? " Failed" : " Got!Prepare to send..."));
//                    if (body == null) {
//                        // error and do nothing
//                        System.out.println("==>" + label + " Done[Failed]");
//                    } else {
//                        if (body.length != 0) {
//                            //构造 AAA消息
//                            byte[] bodyTVL = body;
//                            UcRawMessage aaamsg = new UcRawMessage();
//                            aaamsg.setMessageType(new UcType.UINT1(new byte[]{(byte) 0x81}));
//                            aaamsg.setMessageNo(UcType.newUINT4(1));
//                            aaamsg.setMessageLength(UcType.newUINT4(bodyTVL.length + UcRawMessage.HEADER_LENGTH));
//                            aaamsg.setMessageSequenceNo(UcType.newUINT4(1));
//                            aaamsg.setManaul(false);
//                            aaamsg.setBody(bodyTVL);
//                            // 通过当前连接的DPI的客户端通道发送AAA消息
//                            if (this.dpiEndPoints.get(session).getClientChannel().send_system(aaamsg)) {
//                                System.out.println("=>GOT INFO from AAA Server " + AAAServerIP + " and sent to: " + this.dpiEndPoints.get(session).getDpiEndPointBean().getName() + " successfully");
//                                System.out.println("==>" + label + " Done [Successfully]");
//                            } else {
//                                System.out.println("=>GOT INFO from AAA Server " + AAAServerIP + " and sent to: " + this.dpiEndPoints.get(session).getDpiEndPointBean().getName() + " failed");
//                                System.out.println("==>" + label + " Done [Finished]");
//                            }
//
//                        } else {
//
//                            SearchIpUserRelation r = new SearchIpUserRelation();
//                            List<byte[]> rst = r.search(ip);
//                            System.out.println("=>Search Using SearchIpUserRelation. Found:" + (rst == null ? 0 : rst.size()));
//                            if (rst != null && rst.size() > 0) {
//                                int i = 1;
//                                for (byte[] mb : rst) {
//                                    i++;
//                                    UcRawMessage mmsg = null;
//                                    try {
//                                        mmsg = new UcRawMessage(mb);
//                                    } catch (Exception e) {
//                                        System.out.println("=>SearchIpUserRelation Return Data Error:\n" + HexUtil.getHex(mb));
//                                        continue;
//                                    }
//                                    this.dpiEndPoints.get(session).getClientChannel().send_system(mmsg);
//                                    System.out.println("=>send IPRangeINFO[" + i + "] to DPI : " + this.dpiEndPoints.get(session).getDpiEndPointBean().getName());
//                                }
//                                System.out.println("==>" + label + " Done [Finished]");
//                            } else {
//                                //no such user
//                                byte[] bodyTVL = {0x01, 0x09, 0x4e, 0x6f, 0x6e, 0x2d, 0x45, 0x78, 0x69, 0x73, 0x74};
//                                UcRawMessage aaamsg = new UcRawMessage();
//                                aaamsg.setMessageType(new UcType.UINT1(new byte[]{(byte) 0x81}));
//                                aaamsg.setMessageNo(UcType.newUINT4(1));
//                                aaamsg.setMessageLength(UcType.newUINT4(bodyTVL.length + UcRawMessage.HEADER_LENGTH));
//                                aaamsg.setMessageSequenceNo(UcType.newUINT4(1));
//                                aaamsg.setManaul(false);
//                                aaamsg.setBody(bodyTVL);
//                                // 通过当前连接的DPI的客户端通道发送AAA消息
//                                System.out.println("Prepare Sending AAA Q-REP:No such user:" + JSONObject.fromObject(msg.toJSON()).toString());
//                                if(this.dpiEndPoints.get(session).getClientChannel().send_system(aaamsg)){
//                                    System.out.println("Sending AAA Q-REP:No such user:Successfully" );
//                                }else{
//                                    System.out.println("Sending AAA Q-REP:No such user:Failed.");
//                                }
//
//                                System.out.println("==>" + label + " Done [Finished]");
//                            }
//                            // go liang delin
//                        }
//                    }
//
//                } catch (Exception ex) {
//                    Logger.getLogger(QueryAAA.class.getName()).log(Level.SEVERE, null, ex);
//                }
//            }

        }
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        InetSocketAddress addr = (InetSocketAddress) session.getRemoteAddress();
        if (hibernateSessions.containsKey(session)) {
            hibernateSessions.remove(session).close();
        }
        if (dpiEndPoints.containsKey(session)) {
            DPIEndPoint ep = dpiEndPoints.remove(session);
            ep.getDpiEndPointBean().setIsServerChannelConnected(false);
            ep.persistence();
        }
        System.out.println("server disconnected: " + addr.getAddress().getHostAddress() + " | iosession:" + session.getId() + " | Handler:" + this);

    }

}
